﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using Reticle.Core;
using BNSharp.BattleNet;
using BNSharp;
using System.Xml.Linq;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Reticle
{
    public class PluginInterface : IHost
    {
        private Bot Bot;
        private IPlugin Plug;

        //private object LockCommands = new object();

        public PluginInterface(Bot bot, IPlugin plug)
        {
            Bot = bot;
            Plug = plug;
            DisplayPluginInfo();
            loadEvents();
        }

        #region ICommands Members

        // load all the Battle.net events
        #region Load/Unload Events
        public void loadEvents()
        {
            Bot.client.Connected += new EventHandler(client_Connected);
            Bot.client.Disconnected += new EventHandler(client_Disconnected);
            Bot.client.ServerErrorReceived += new ServerChatEventHandler(client_ServerErrorReceived);
            Bot.client.InformationReceived += new ServerChatEventHandler(client_InformationReceived);
            Bot.client.EnteredChat += new EnteredChatEventHandler(client_EnteredChat);
            Bot.client.JoinedChannel += new ServerChatEventHandler(client_JoinedChannel);
            Bot.client.MessageSent += new ChatMessageEventHandler(client_MessageSent);
            Bot.client.UserEmoted += new ChatMessageEventHandler(client_UserEmoted);
            Bot.client.UserFlagsChanged += new UserEventHandler(client_UserFlagsChanged);
            Bot.client.UserJoined += new UserEventHandler(client_UserJoined);
            Bot.client.UserLeft += new UserEventHandler(client_UserLeft);
            Bot.client.UserShown += new UserEventHandler(client_UserShown);
            Bot.client.UserSpoke += new ChatMessageEventHandler(client_UserSpoke);
            Bot.client.WhisperReceived += new ChatMessageEventHandler(client_WhisperReceived);
            Bot.client.WhisperSent += new ChatMessageEventHandler(client_WhisperSent);
        }

        // unload all the events (when plugin is unloaded)
        public void unloadEvents()
        {
            Bot.client.Connected -= new EventHandler(client_Connected);
            Bot.client.Disconnected -= new EventHandler(client_Disconnected);
            Bot.client.ServerErrorReceived -= new ServerChatEventHandler(client_ServerErrorReceived);
            Bot.client.InformationReceived -= new ServerChatEventHandler(client_InformationReceived);
            Bot.client.EnteredChat -= new EnteredChatEventHandler(client_EnteredChat);
            Bot.client.JoinedChannel -= new ServerChatEventHandler(client_JoinedChannel);
            Bot.client.MessageSent -= new ChatMessageEventHandler(client_MessageSent);
            Bot.client.UserEmoted -= new ChatMessageEventHandler(client_UserEmoted);
            Bot.client.UserFlagsChanged -= new UserEventHandler(client_UserFlagsChanged);
            Bot.client.UserJoined -= new UserEventHandler(client_UserJoined);
            Bot.client.UserLeft -= new UserEventHandler(client_UserLeft);
            Bot.client.UserShown -= new UserEventHandler(client_UserShown);
            Bot.client.UserSpoke -= new ChatMessageEventHandler(client_UserSpoke);
            Bot.client.WhisperReceived -= new ChatMessageEventHandler(client_WhisperReceived);
            Bot.client.WhisperSent -= new ChatMessageEventHandler(client_WhisperSent);
        }
        #endregion

        #region Battle.Net Plugin Events
        void client_UserSpoke(object sender, ChatMessageEventArgs e)
        {
            Plug.UserSpoke(sender, e);
        }

        void client_UserShown(object sender, UserEventArgs e)
        {
            Plug.UserShown(sender, e);
        }

        void client_UserLeft(object sender, UserEventArgs e)
        {
            Plug.UserLeft(sender, e);
        }

        void client_UserJoined(object sender, UserEventArgs e)
        {
            Plug.UserJoined(sender, e);
        }

        void client_UserFlagsChanged(object sender, UserEventArgs e)
        {
            Plug.UserFlagsChanged(sender, e);
        }

        void client_UserEmoted(object sender, ChatMessageEventArgs e)
        {
            Plug.UserEmoted(sender, e);
        }

        void client_MessageSent(object sender, ChatMessageEventArgs e)
        {
            Plug.MessageSent(sender, e);
        }

        void client_JoinedChannel(object sender, ServerChatEventArgs e)
        {
            Plug.JoinedChannel(sender, e);
        }

        void client_EnteredChat(object sender, EnteredChatEventArgs e)
        {
            Plug.EnteredChat(sender, e);
        }

        void client_Disconnected(object sender, EventArgs e)
        {
            Plug.Disconnected(sender, e);
        }

        void client_Connected(object sender, EventArgs e)
        {
            Plug.Connected(sender, e);
        }

        void client_ServerErrorReceived(object sender, ServerChatEventArgs e)
        {
            Plug.ServerErrorReceived(sender, e);
        }

        void client_InformationReceived(object sender, ServerChatEventArgs e)
        {
            Plug.InformationReceived(sender, e);
        }

        void client_WhisperReceived(object sender, ChatMessageEventArgs e)
        {
            Plug.WhisperReceived(sender, e);
        }

        void client_WhisperSent(object sender, ChatMessageEventArgs e)
        {
            Plug.WhisperSent(sender, e);
        }
        #endregion

        // adds chat to the screen
        public void AddChat(string color, string message)
        {
            if (Bot.BotKey == Program.Window.CurrentTabKey())
            {
                Program.Window.InvokeScript(Bot.BotKey, Program.Window.checkSetting("chatevent"), "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span style=\"color:" + color + ";\">" + Helper.ConvertUrlsToLinks(message) + "</span></div>");
                Program.Window.AddChat(Bot.BotKey, "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span style=\"color:" + color + ";\">" + Helper.ConvertUrlsToLinks(message) + "</span></div>");
            }
            else
            {
                Program.Window.AddChat(Bot.BotKey, "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span style=\"color:" + color + ";\">" + Helper.ConvertUrlsToLinks(message) + "</span></div>");
            }
        }

        // sends a message to Battle.net
        public void Send(string message)
        {
            //Bot.SendMessage(message);
            Bot.Enqueue(message);
        }

        public void ShowForm(object frm)
        {
            try
            {
                ((Form)frm).Show();
            }
            catch
            {

            }
        }

        public void UnloadPlugin()
        {
            // remove from menu blah blah
            unloadEvents();
            Bot.Plugins.Remove(Plug);
            Bot.PluginMenu.DropDownItems.RemoveByKey(Plug.Filename);
            Bot.CreateMenu();

            AddChat("yellow", Plug.Filename + " has been unloaded.");
        }

        public BattleNetClient Client
        {
            get { return Bot.client; }
            set { Bot.client = value; }
        }

        public void SetPluginMenu(ToolStripMenuItem menu)
        {
            if (menu == null)
                return;
            EventHandler e = new EventHandler(pluginMenu_Click);
            menu.Name = Plug.Filename;
            menu.DropDownItems.Add(PluginFunctions.NewToolMenu("Unload", "Unload", e));
            Bot.PluginMenu.DropDownItems.Add(menu);
            Bot.CreateMenu();
            //BotCore.Main.MenuChanged(Bot);
        }

        void pluginMenu_Click(object sender, EventArgs e)
        {
            if (Bot.IsPluginLoaded(Plug.Filename))
            {
                Plug.Unload();
            }
        }

        public void DisplayPluginInfo()
        {
            AddChat("white", "Loaded plugin " + Plug.Filename);
            AddChat("#00FF00", "Name: " + Plug.Name);
            AddChat("#00FF00", "Author: " + Plug.Author);
            AddChat("#00FF00", "Description: " + Plug.Description);
        }

        public object GetVersion()
        {
            return "Reticle v1.0 Alpha 4 by Scope";
        }

        public bool IsConnected()
        {
            return Bot.IsConnected();
        }

        public string CurrentChannel()
        {
            return Bot.CurrentChannel;
        }

        // retrieve value from config.xml (for the bot the plugin is loaded on)
        public object GetConfigSetting(string variablename)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");

            foreach (XElement xe in doc.Descendants("Profile"))
            {
                if (xe.Element("id").Value == Bot.BotKey)
                {
                    return xe.Element(variablename).Value;
                }
            }

            return null;
        }

        // save value to config.xml (for the profile the bot is loaded on)
        public void SaveConfigSetting(string variablename, object variable)
        {
            try
            {
                XDocument doc = XDocument.Load(Application.StartupPath + @"\files\config.xml");

                foreach (XElement xe in doc.Descendants("Profile"))
                {
                    if (xe.Element("id").Value == Bot.BotKey)
                    {
                        xe.Element(variablename).Value = (string)variable;
                    }
                }

                doc.Save(Application.StartupPath + @"\files\config.xml");
            }
            catch (Exception) { }
        }

        // retrieve value from plugins.xml
        public object GetPluginSetting(string variablename)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\plugins.xml");

            // if Bot Key (id) is not alphanumeric, convert it
            string bot = Regex.Replace(Bot.BotKey, @"[\W]", "");

            try
            {
                foreach (XElement xe in doc.Descendants(bot + "-" + Plug.Filename))
                {
                    if (xe.Element(variablename).Name == variablename)
                    {
                        return xe.Element(variablename).Value;
                    }
                }
            }
            catch (Exception) { }

            /*catch (Exception ex)
            {
                string exception = string.Format("Error: ({0}) Problem with GetPluginSetting(\"{1}\")<br />{2}<br />{3}<br />{4}<br />{5}<br />{6}<br />{7}", Plug.Filename, variablename, ex.Message, ex.Source, ex.StackTrace, ex.TargetSite, ex.InnerException, ex.HelpLink);
                AddChat("red", exception);
            }*/

            return null;
        }

        // set value in plugins.xml
        public void SavePluginSetting(string variablename, object variable)
        {
            XDocument doc = XDocument.Load(Application.StartupPath + @"\files\plugins.xml");

            // if Bot Key (id) is not alphanumeric, convert it
            string bot = Regex.Replace(Bot.BotKey, @"[\W]", "");

            // if no settings are present in the plugin file, create the root node
            if (doc.Descendants(bot + "-" + Plug.Filename).Count() <= 0)
            {
                XElement elem = new XElement(bot + "-" + Plug.Filename);

                doc.Element("Plugins").Add(elem);
            }

            // if the setting doesn't exist, add it too.
            var found = doc.Element("Plugins").Element(bot + "-" + Plug.Filename).Element(variablename);
            if (found == null)
            {
                // Add the element
                XElement elem = new XElement(variablename, (string)variable);
                doc.Element("Plugins").Element(bot + "-" + Plug.Filename).Add(elem);
            }
            // setting exists, lets modify it
            else
            {
                doc.Element("Plugins").Element(bot + "-" + Plug.Filename).Element(variablename).Value = (string)variable;
            }

            doc.Save(Application.StartupPath + @"\files\plugins.xml");
        }
        #endregion
    }
}
